import abc
from typing import List, TypeVar, Generic, Union

from pywebio.io_ctrl import Output
from pywebio.output import OutputPosition

from emi.model import PageResult,default_page_result
from emi.util import AsyUtil
from emiui import UISession
import pywebio
import pywebio_battery
from pywebio import pin, output

ItemType = TypeVar("ItemType")
DataType = TypeVar("DataType")


class DataListView(Generic[ItemType,DataType]):

    def __init__(self,
                 name: str,
                 datas: Union[List[ItemType],PageResult[ItemType]],
                 ui_session: UISession = None,
                 page_size = 50
                 ):
        self.PAGE_SIZE = page_size
        self.NAME = name
        self.PREFIX = f"{name}_dlv"
        self.ui_session = ui_session
        if isinstance(datas,PageResult):
            self.page_result = datas
        elif isinstance(datas,list):
            self.page_result = default_page_result(datas,page_size)
        else:
            raise NotImplementedError()

    @abc.abstractmethod
    def get_item_view(self,offset:int,is_head:bool,data:DataType)->Output:
        """
        获取列表元素。
        :param offset:  序号
        :param is_head:  是否列表头部
        :param data:
        :return:
        """
        pass

    def load_item_data(self,items:List[ItemType])->List[DataType]:
        """
        加载item信息的详情数据
        :param items:
        :return:
        """
        return items


    async def show(self):
        if self.ui_session is None:
            self.ui_session = UISession.get()
        output.put_scope(name=f"{self.PREFIX}_DataListView")
        await self.refresh()


    async def refresh(self):
        page_result = self.page_result
        with output.use_scope(name=f"{self.PREFIX}_DataListView",clear=True):
            _option_data_ = []
            selected_index = page_result.cur_page()
            for page_index in range(1, page_result.total_page_count() + 1):
                _option_data_.append({
                    "label": f"第{page_index}页",
                    "value": page_index,
                    "selected": selected_index == page_index
                }
                )

            async def __refresh_data():
                page_index = await pin.pin[f"{self.PREFIX}_pages"]
                if page_index is not None:
                    await self._load_page_at(page_index)

            output.put_row([
                output.put_button(label="刷新", onclick=__refresh_data),
                pin.put_select(f"{self.PREFIX}_pages", options=_option_data_).style("margin-left:10px"),
                output.put_scope(f"{self.PREFIX}_pages_desc"),

            ], size='70px 100px auto')

            pin.pin_on_change(f"{self.PREFIX}_pages", onchange=self._load_page_at,clear=True)

            output.put_scope(f"{self.PREFIX}_result")

            if page_result.total_page_count() > 0:
                await self._load_page_at(1)

    async def _load_page_at(self,index):
        with output.use_scope(f"{self.PREFIX}_pages_desc", clear=True):
            pass
        with output.use_scope(f"{self.PREFIX}_result",clear=True):
            output.put_loading()

        async def _on_load_finished(data_list:List[DataType]):
            with output.use_scope(f"{self.PREFIX}_pages_desc", clear=True):
                output.put_text(f"共有{self.page_result.total_count()}个数据，"
                                f"当前显示页面: {self.page_result.cur_page()}/{self.page_result.total_page_count()}",
                                position=OutputPosition.BOTTOM).style("margin-top:10px;margin-left:10px")

            with output.use_scope(f"{self.PREFIX}_result", clear=True):
                table_data = []
                table_data.append(self.get_item_view(0,is_head=True, data = None))
                for index, data in enumerate(data_list):
                    offset = (self.page_result.cur_page() - 1) * self.page_result.page_size() + index + 1
                    table_data.append(self.get_item_view(offset,is_head=False, data = data))
                output.put_table(table_data)

        def _load_page_data():
            self.page_result.turn_page(index) ### 跳转页面或者刷新
            items:List[ItemType] = self.page_result.get_data()
            data_list:List[DataType] = self.load_item_data(items)
            self.ui_session.post(_on_load_finished(data_list))

        AsyUtil.run_in_thread(_load_page_data)